package Thread;

import java.util.concurrent.PriorityBlockingQueue;

/**
 * Created with IntelliJ IDEA.
 * Description: 线程模式之计时器
 */
class MyTimer2 {
    private Object locker = new Object();
    //属性：(时间， 任务)
    // 1.计时器需要选择时间最近的任务执行，因此时间和任务应该包装在一起，创建一个内部类
    private static class Work implements Comparable<Work> {
        //任务直接使用Runnable来描述
        private Runnable task;
        private long time;

        public Work(Runnable task, long time) {
            this.task = task;
            //传入的时间是相对时间，我们需要转成绝对时间来和系统时间进行比较
            this.time = time + System.currentTimeMillis();
        }

        @Override
        public int compareTo(Work o) {
            return (int) (this.time - o.time);
        }
    }

    // 2.描述任务之后就需要一个组织任务的数据结构，可以选择优先级阻塞队列，由于是优先级队列，因此我们需要work可以比较
    private PriorityBlockingQueue<Work> queue = new PriorityBlockingQueue<>();
    // 3.创建一个线程，让这个线程来不断的扫描任务，看是否到时间了，在构造方法中启动
    private Thread worker = new Thread() {
        @Override
        public void run() {
            //忙等,极大浪费CPU资源，加锁
            while(true) {
                try {
                    Work tmp = queue.take();
                    long srctime = System.currentTimeMillis();
                    if(tmp.time > srctime) {
                        queue.put(tmp);
                        synchronized (locker) {
                            locker.wait(tmp.time - srctime);
                        }
                        continue;
                    }
                    tmp.task.run();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    };

    // 4.为用户创建一个公开的方法，方便用户将任务传进来
    public void schedule(Runnable task, long time) {
        Work newWork = new Work(task, time);
        //每次有新的任务加进来，都判断一次
        queue.put(newWork);
        //注意：锁只需要包住notify方法即可
        synchronized (locker) {
            locker.notify();
        }
    }

    //构造方法，启动工作线程
    public MyTimer2() {
        worker.start();
    }
}

public class ThreadDemo34 {
    public static void main(String[] args) {
        MyTimer2 timer2 = new MyTimer2();
        timer2.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello");
            }
        }, 1000);
        timer2.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("timer");
            }
        }, 500);
        System.out.println("main");
    }
}
